// =============================================================================
//  Spangles Analyzer
//
//  Copyright(c) 2008
//  See LICENSE.txt for licensing information.
// =============================================================================

package com.google.spangles.domain;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * (Description) (Any invariants [conditions that are always true] ) (Usage
 * instructions, and/or examples) (TODOs, ASSUMPTIONs, etc.) (Known Bugs)
 * (Concurrency strategy - not thread safe or how it's thread safe)
 * 
 * @author Chris
 */
public class CanonicalPosition extends Position
{
   public CanonicalPosition(Color color, Map<Location, Color> pieces)
   {
      super(color, Collections.unmodifiableMap(pieces));
   }
   
   /**
    * @param expected
    */
   public CanonicalPosition(byte[] encoding)
   {
      int xs = encoding[0] & 0x7f;
      int ys = encoding[1] & 0x7f;
      
      boolean isBlack = ((encoding[0] & 0x80) != 0);
      
      toMove = Color.WHITE;
      if(isBlack)
      {
         toMove=Color.BLACK;
      }
      
      boolean isOffset = ((encoding[1] & 0x80) != 0);
      
      int x1=0;
      int x2=x1+xs-1;
      int y1=0;
      if(isOffset)
      {
         y1++;
      }
      int y2=y1+ys-1;
      
      int index = 2;
      int trits = 0;
      int buffer = 0;
      
      layout = new HashMap<Location, Color>();
      
      for(int y=y1;y<=y2;y++)
      {
         for(int x=x1;x<=x2;x++)
         {
            if(trits==0)
            {
               buffer = 0x00ff & encoding[index++];
               trits = 4;
            }
            int trit = buffer % 4;
            buffer /= 4;
            trits --;
            
            if(trit != 0)
            {
               Location l = new Location(x,y);
               if(trit==1)
               {
                  layout.put(l, Color.WHITE);
               }
               else if(trit==2)
               {
                  layout.put(l, Color.BLACK);                  
               }
               else if(trit==3)
               {
                  layout.put(l, Color.GRAY);
               }
            }
         }
      }
   }

   public CanonicalPosition canonicalize()
   {
      return this;
   }

   /**
    * (Description - what the method does and why)
    * (Visibility decision, if not obvious)
    * (Pre/Post Conditions)
    * (Usage examples)
    * (Algorithmic notes)
    * (Concurrency issues)
    * @return
    */
   public byte[] getEncoding()
   {
      Color toMove = getToMove();
      
      int x1 = getMinimumX();
      int x2 = getMaximumX();
      int xs = x2-x1+1;
      
      int y1 = getMinimumY();
      int y2 = getMaximumY();
      int ys = y2-y1+1;
      
      int cells = (xs*ys);
      int bytes = (cells+3)/4;
      
      byte[] out = new byte[bytes+2];
      
      int b0 = xs;
      if(toMove.equals(Color.BLACK))
      {
         b0+=0x80;
      }
      out[0] = (byte)b0;
      
      int b1 = ys;
      if(y1 != 0)
      {
         b1 += 0x80;
      }
      out[1] = (byte)b1;
      
      int buffer = 0;
      int placeValue = 1;
      int index = 2;
      
      for(int y=y1;y<=y2;y++)
      {
         for(int x=x1;x<=x2;x++)
         {
            Color c = getPiece(new Location(x,y));
            int value = 0;
            
            if(Color.WHITE.equals(c))
            {
               value = 1;
            }
            else if(Color.BLACK.equals(c))
            {
               value = 2;
            }
            else if(Color.GRAY.equals(c))
            {
               value = 3;
            }
            
            buffer += (placeValue*value);
            placeValue *= 4;
            
            if (placeValue == 256)
            {
               out[index++] = (byte)buffer;
               buffer = 0;
               placeValue = 1;
            }
         }
      }
      
      if (placeValue != 1)
      {
         out[index++] = (byte)buffer;         
      }
      
      return out;
   }

   /* (non-Javadoc)
    * @see com.google.spangles.domain.Position#putPiece(com.google.spangles.domain.Color, com.google.spangles.domain.Location)
    */
   public Position putPiece(Color color, Location l)
   {
      Map<Location, Color> newMap = new HashMap<Location, Color>();
      newMap.putAll(layout);
      Position p = new Position(toMove, newMap);
      
      return p.putPiece(color, l);
   }
}
